use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime, Utc};
use pom::parser::*;

fn space<'a>() -> Parser<'a, char, ()> {
    one_of(" \t\r\n").repeat(0..).discard()
}
fn year<'a>() -> Parser<'a, char, i32> {
    one_of("0123456789").repeat(4).map(|s: Vec<char>| {
        let s: String = s.into_iter().collect();
        s.parse::<i32>().unwrap()
    })
}
fn one_or_two_num<'a>() -> Parser<'a, char, u32> {
    one_of("0123456789").repeat(1..3).map(|s: Vec<char>| {
        let s: String = s.into_iter().collect();
        s.parse::<u32>().unwrap()
    })
}
fn two_num<'a>() -> Parser<'a, char, u32> {
    one_of("0123456789").repeat(2).map(|s: Vec<char>| {
        let s: String = s.into_iter().collect();
        s.parse::<u32>().unwrap()
    })
}
fn date<'a>() -> Parser<'a, char, Option<NaiveDate>> {
    let sc1 = sym('-') | sym('/') | sym('年') | sym('.');
    let sc2 = sym('-') | sym('/') | sym('月') | sym('.');
    let date = space() * (year() + two_num() + two_num())
        | (year() - sc1 + one_or_two_num() - sc2 + one_or_two_num()) - any().repeat(0..);
    date.map(|((year, month), day)| NaiveDate::from_ymd_opt(year, month, day))
}
fn date_time<'a>() -> Parser<'a, char, Option<DateTime<Utc>>> {
    let sc1 = sym('-') | sym('/') | sym('年') | sym('.');
    let sc2 = sym('-') | sym('/') | sym('月') | sym('.');
    let sc4 = sym(':') | sym('-') | sym('.');
    let sc5 = sym(':') | sym('-') | sym('.');
    let date_time1 = year() + two_num() + two_num() - sym(' ') + two_num() + two_num() + two_num();
    let date_time2 =
        year() - sc1 + one_or_two_num() - sc2 + one_or_two_num() - sym(' ') + one_or_two_num() - sc4
            + one_or_two_num()
            - sc5
            + one_or_two_num();
    let date_time = space() * (date_time1 | date_time2) - any().repeat(0..);
    date_time.map(|(((((year, month), day), hour), minute), second)| {
        if let Some(nd) = NaiveDate::from_ymd_opt(year, month, day) {
            if let Some(nt) = NaiveTime::from_hms_opt(hour, minute, second) {
                let ndt = NaiveDateTime::new(nd, nt);
                return Some(DateTime::<Utc>::from_naive_utc_and_offset(ndt, Utc));
            }
        }
        None
    })
}
pub fn parse_date(s: &str) -> anyhow::Result<NaiveDate> {
    let input: Vec<char> = s.chars().collect();
    let val = date().parse(&input);
    match val {
        Ok(d) => {
            if let Some(d) = d {
                Ok(d)
            } else {
                Err(anyhow::anyhow!("值{s}不是有效的日期类型"))
            }
        }
        Err(err) => Err(anyhow::anyhow!("值{s}不是有效的日期类型:{err}")),
    }
}
pub fn parse_date_time(s: &str) -> anyhow::Result<DateTime<Utc>> {
    let input: Vec<char> = s.chars().collect();
    let v = if let Ok(Some(d)) = date_time().parse(&input) {
        Ok(d)
    } else {
        return Err(anyhow::anyhow!("值{}不是有效的日期类型", s));
    };
    v
}
fn extract_month(s: &str) -> anyhow::Result<String> {
    let input: Vec<char> = s.chars().collect();
    let val = (year() - sym('年') + two_num() - sym('月')).parse(&input);
    match val {
        Ok((year, month)) => Ok(format!("{}{:02}", year, month)),
        Err(_err) => Err(anyhow::anyhow!("{}中没有类似[2025年8月]的月份信息", s)),
    }
}
